package falcon.common;

public final class FalconHost {

	public static int get(FalconConfig config, String host, int port, String user, String[] rs) {
		String path = FalconStore.getPath(NAME, config);
		if (!TextFile.exists(path)) {
			Log.log("conf not found;path=%s", path);
			return Errno.COM_NOT_FOUND;
		}
		String[] lines = TextFile.readLines(path);
		if (lines == null) {
			Log.log("read conf failure;path=%s", path);
			return Errno.COM_READ_FILE_ERROR;
		}
		String line = find(lines, host);
		if (line == null) {
			Log.log("host not found;host=%s", host);
			return Errno.VERIF_HOST_FORBIDDEN;
		}
		String[] array = line.split(" ");
		if (array.length != 3) {
			Log.log("array.length != 3;host=%s", host);
			return Errno.COM_ARGS_INVALID;
		}
		String cipher = array[1];
		long timestamp = Long.parseLong(array[2]);
		String data = decrypt(cipher, host, port, user, timestamp);
		if (data == null) {
			Log.log("decrypt failure;host=%s", host);
			return Errno.COM_CATCH_EXCEPTION;
		}
		String password = checkData(data, timestamp);
		if (password == null) {
			Log.log("check data failure;host=%s", host);
			return Errno.VERIF_PASSWORD_ERROR;
		}
		rs[0] = password;
		return Errno.SUCCESS;
	}
	
	public static int add(FalconConfig config, String cipher, String host, int port, String user, long timestamp) {
		String data = decrypt(cipher, host, port, user, timestamp);
		if (data == null) {
			Log.log("decrypt failure;host=%s", host);
			return Errno.COM_CATCH_EXCEPTION;
		}
		String password = checkData(data, timestamp);
		if (password == null) {
			Log.log("check data failure;host=%s", host);
			return Errno.COM_ARGS_INVALID;
		}
		String path = FalconStore.getPath(NAME, config);
		if (!TextFile.exists(path)) {
			String line = String.format("%s %s %d\n", host, cipher, timestamp);
			return TextFile.write(path, line.toString(), false);
		}
		String[] lines = TextFile.readLines(path);
		if (lines == null) {
			Log.log("read conf failure;path=%s", path);
			return Errno.COM_READ_FILE_ERROR;
		}
		String line = find(lines, host);
		if (line != null) {
			Log.log("host exists;host=%s", host);
			return Errno.COM_EXISTS;
		}
		boolean insert = false;
		StringBuilder sb = new StringBuilder(1024);
		for (int i = 0; i < lines.length; i ++) {
			line = lines[i];
			// 复用以前删除的空行
			if ("".equals(line) && !insert) {
				insert = true;
				sb.append(String.format("%s %s %d\n", host, cipher, timestamp));
			} else {
				sb.append(line);
				sb.append('\n');
			}
		}
		if (!insert) {
			sb.append(String.format("%s %s %d\n", host, cipher, timestamp));
		}
		TextFile.write(path, sb.toString(), false);
		return Errno.SUCCESS;
	}
	
	public static int remove(FalconConfig config, String cipher, String host, int port, String user, long timestamp) {
		String data = decrypt(cipher, host, port, user, timestamp);
		if (data == null) {
			Log.log("decrypt failure;host=%s", host);
			return Errno.COM_CATCH_EXCEPTION;
		}
		String password = checkData(data, timestamp);
		if (password == null) {
			Log.log("check data failure;host=%s", host);
			return Errno.COM_ARGS_INVALID;
		}
		String path = FalconStore.getPath(NAME, config);
		if (!TextFile.exists(path)) {
			Log.log("conf not found;path=%s", path);
			return Errno.COM_NOT_FOUND;
		}
		String[] lines = TextFile.readLines(path);
		if (lines == null) {
			Log.log("read conf failure;path=%s", path);
			return Errno.COM_READ_FILE_ERROR;
		}
		String line = find(lines, host);
		if (line == null) {
			Log.log("host not found;host=%s", host);
			return Errno.COM_NOT_FOUND;
		}
		StringBuilder sb = new StringBuilder(1024);
		for (int i = 0; i < lines.length; i ++) {
			String l = lines[i];
			// 移除指定行的数据
			if (!line.equals(l)) {
				sb.append(l);
			}
			sb.append('\n');
		}
		TextFile.write(path, sb.toString(), false);
		return Errno.SUCCESS;
	}
	
	public static String encrypt(String password, String host, int port, String user, long timestamp) {
		String[] keyArray = new String[3];
		keyArray[0] = Md5.get(user);
		keyArray[1] = Md5.get(host);
		keyArray[2] = Md5.get(Long.toString(timestamp));
		String data = String.format("%d_%s", timestamp, password);
		return Security.encrypt(keyArray, data);
	}

	public static String decrypt(String cipher, String host, int port, String user, long timestamp) {
		String[] keyArray = new String[3];
		keyArray[0] = Md5.get(user);
		keyArray[1] = Md5.get(host);
		keyArray[2] = Md5.get(Long.toString(timestamp));
		return Security.decrypt(keyArray, cipher);
	}
	
	private static String find(String[] lines, String host) {
		for (int i = 0; i < lines.length; i ++) {
			String line = lines[i];
			if ("".equals(line)) {
				continue;
			}
			String[] array = line.split(" ");
			if (array.length != 3) {
				continue;
			}
			String h = array[0];
			if (!host.equals(h)) {
				continue;
			}
			return line;
		}
		return null;
	}
	
	private static String checkData(String data, long timestamp) {
		int idx = -1;
		for (int i = 0; i < data.length(); i ++) {
			char ch = data.charAt(i);
			if (ch >= '0' && ch <= '9') {
				continue;
			}
			idx = i;
			break;
		}
		if (idx < 0) {
			return null;
		}
		if (data.charAt(idx) != '_') {
			return null;
		}
		String value = data.substring(0, idx);
		if (!value.equals(Long.toString(timestamp))) {
			return null;
		}
		return data.substring(idx + 1);
	}
	
	private static final String NAME = "host.conf";
}
